Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow Clients with Optional Client Auth to not negotiate Client Auth #816

Merged
merged 3 commits into from
Aug 2, 2018

Conversation

alexw91
Copy link
Contributor

@alexw91 alexw91 commented Jul 25, 2018

Issue # (if available): #815

Description of changes:
Fix Client side bug in handling Optional Client Auth.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

Copy link
Contributor

@baldwinmatt baldwinmatt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, one comment

}

/* If server, and Client Auth is REQUIRED or OPTIONAL, then the server must send the CLIENT_CERT_REQ Message*/
if (conn->mode == S2N_SERVER && client_cert_auth_type != S2N_CERT_AUTH_NONE) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else if?

S2N_SERVER and S2N_CLIENT are mutually exclusive, so make this an else?


if (conn->mode == S2N_CLIENT && client_cert_auth_type == S2N_CERT_AUTH_REQUIRED) {
/* If we're a client, and Client Auth is REQUIRED, then the Client must expect the CLIENT_CERT_REQ Message */
conn->handshake.handshake_type |= CLIENT_AUTH;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the client is dynamically reacting to the presence of a CertificateRequest now, do we still need to have the client explicitly setting a client auth mode?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're still honoring the client_cert_auth_type value.

If it's NONE we'll abort the handshake rather than enter the ClientCertRequest state, if OPTIONAL we'll enter that state only if the Server asks and potentially send an empty response if no ClientCert is configured, and if REQUIRED we'll always expect the ClientCertRequest from the server and abort the handshake if no ClientCert is configured.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I think my comment was a little confusing. I meant to ask if we could relax the constraint of REQUIRED altogether. Could the client just dynamically react to the CertificateRequest in all cases (REQUIRED, OPTIONAL, and NONE)? If it has a client cert configured and it receives a CertificateRequest, send the cert. If it does not have a client cert configured and it receives a CertificateRequest, send an empty response. If no CertificateRequest is sent, carry on.

If the client is configured to REQUIRED and the server does not send the CertificateRequest, why fail the handshake? Why not just let the server decide the requirements of client authentication? Maybe I'm missing a use case or complexity here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there are clients out there that would expect to fail if the server doesnt support mutual auth. by allowing it to succeed and having the server decide what to do, you are potentially allowing your client to start communicating with an untrusted or unexpected server.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, wouldn't the client still have authenticated the server to ensure it was communicating with a trusted endpoint? The server would have still sent it's own certificate. The client could enforce server auth without having to enforce mutual auth.

Copy link
Contributor Author

@alexw91 alexw91 Jul 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is an API design discussion. If a developer configures their s2n client with CERT_AUTH_NONE, what are they trying to say?

I see two plausible options:

  1. "I don't want to connect to any servers that request Client Auth, abort the handshake if a Client Cert is requested"
  2. "I never want to send any Client Certs, just send an empty ClientCert message if necessary, and let the server decide to abort the handshake if necessary"

The 2nd option is better for compatibility reasons, since the client can connect to more Servers (those that always request a ClientCert but don't require it), but the 2nd option has exactly the same behavior as an s2n Client with no ClientCert configured with CERT_AUTH_OPTIONAL (and it seems weird for someone to add a ClientCert but set ClientCertAuth to NONE).

If we adopt the 2nd option, the behavior of the 1st option can also be replicated manually by calling s2n_connection_client_cert_used() after the handshake is completed, and aborting the handshake if necessary, but that requires more work on the developer's part.

I'm okay going either way.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea of optional client certs doesn't map to the client very well. The RFC says:

If no suitable certificate is available, the client MUST send a certificate message containing no certificates.
...
If the client does not send any certificates, the server MAY at its discretion either continue the handshake without client authentication, or respond with a fatal handshake_failure alert.

I interpret that as basically saying the RFC doesn't even really allow for clients deciding to end the handshake based on the existence (or lack of) a certificate request. The rules for either party of a handshake sending an error are a little fuzzy in that you could interpret it to mean that if an implementation decides something is an error then it can bail-out, but I interpret it more that if an error as defined by the RFC is encountered then bail out. Since the client certificate portion doesn't allow the client to determine that there's been an error, it wouldn't be valid for the client to bail-out here.

All that is to say that per the RFC, I think setting any of the REQUIRED/OPTIONAL/NONE in a client context is invalid. If the consumer, at the application level, wants to require the use of a client cert then s2n_connection_client_cert_used() is the mechanism for allowing that (after the handshake is complete).

If you want a feature that allows the client to bail out of connections based on the server's client certificate behavior, I think there's probably a few use-cases for that and it wouldn't be a big deal in practice, but I don't think it would be compliant with the RFC.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opened #819 to continue this discussion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants